﻿using System;
using System.Collections.Generic;
using Microsoft.SharePoint;
using Kiiro.Common.Entities;
using Kiiro.Common.Utility;
using Kiiro.DataAccess;
using Kiiro.ExceptionManagement;
using Kiiro.Validation.Validators.Entities;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Administration;

namespace Kiiro.Model
{
    public class TeamModel
    {
        /// <summary>
        /// Gets the team member for the supplied user id and project url
        /// </summary>
        /// <param name="userId">The user id of the team member to find</param>
        /// <param name="siteCollectionId">The site collection id</param>
        /// <param name="serverRelativeUrl">The server relative url to the project site</param>
        public static TeamMember GetTeamMemberByUserId ( int userId, Guid siteCollectionId, string serverRelativeUrl )
        {
            List<TeamMember> members = TeamDA.Instance.GetTeamMembersByUserIds ( new List<int> ( ) { userId }, siteCollectionId, serverRelativeUrl );
            List<User> users = UserModel.GetUsersByIds ( new List<int> ( ) { userId }, siteCollectionId, serverRelativeUrl );

            TeamMember member = members.Find ( x => x.UserId == userId );
            
            if ( member != null )
                member.User = users.Find ( x => x.Id == member.UserId );

            return member;
        }

        /// <summary>
        /// Get ALL team members for a project
        /// </summary>
        /// <param name="siteCollectionId">The site collection id</param>
        /// <param name="serverRelativeUrl">The project site server relative url</param>
        public static List<TeamMember> GetTeamMembers ( Guid siteCollectionId, string serverRelativeUrl )
        {
            List<TeamMember> members = TeamDA.Instance.GetTeamMembersByUserIds ( new List<int> ( ), siteCollectionId, serverRelativeUrl );

            List<int> userIds = new List<int> ( );
            foreach ( TeamMember member in members )
                userIds.Add ( member.UserId );

            List<User> users = UserModel.GetUsersByIds ( userIds, siteCollectionId, serverRelativeUrl );

            foreach ( TeamMember member in members )
                member.User = users.Find ( x => x.Id == member.UserId );

            members.RemoveAll ( x => x.User == null );

            return members;
        }

        /// <summary>
        /// Gets a TeamMember entity
        /// </summary>
        /// <param name="teamMemberId">The team member id to get</param>
        /// <param name="siteCollectionId">The site collection id</param>
        /// <param name="serverRelativeUrl">The server relative url</param>
        public static TeamMember GetTeamMembersById ( int teamMemberId, Guid siteCollectionId, string serverRelativeUrl )
        {
            TeamMember member = null;
            List<TeamMember> members = GetTeamMembersByIds ( new List<int> ( ) { teamMemberId }, siteCollectionId, serverRelativeUrl );

            if ( members.Count > 0 )
                member = members [ 0 ];

            return member;
        }

        /// <summary>
        /// Gets a list of TeamMember entities. If teamMemberIds is null or empty this method returns ALL TeamMembers.
        /// </summary>
        /// <param name="teamMemberIds">The list of team member ids to get. If teamMemberIds is null or empty this method returns ALL TeamMembers.</param>
        /// <param name="siteCollectionId">The site collection id</param>
        /// <param name="serverRelativeUrl">The server relative url</param>
        /// <returns>If teamMemberIds is null or empty this method returns ALL TeamMembers.</returns>
        public static List<TeamMember> GetTeamMembersByIds ( List<int> teamMemberIds, Guid siteCollectionId, string serverRelativeUrl )
        {
            List<TeamMember> members = TeamDA.Instance.GetTeamMembersByIds ( teamMemberIds, siteCollectionId, serverRelativeUrl );

            List<int> userIds = new List<int> ( );
            foreach ( TeamMember member in members )
                userIds.Add ( member.UserId );

            List<User> users = UserModel.GetUsersByIds ( userIds, siteCollectionId, serverRelativeUrl );

            foreach ( TeamMember member in members )
                member.User = users.Find ( x => x.Id == member.UserId );

            members.RemoveAll ( x => x.User == null );

            return members;
        }




        internal static List<TeamMember> Save ( List<TeamMember> members, Project project, Guid siteCollectionId, string serverRelativeUrl )
        {
            //bool groupsSet = false;

            try
            {
                if ( members != null )
                {
                    if ( project == null )
                        project = ProjectsModel.GetByServerRelativeWebUrl ( siteCollectionId, serverRelativeUrl );

                    foreach ( TeamMember teamMember in members )
                    {
                        if ( teamMember != null && teamMember.EditType != EditType.Unchanged )
                        {
                            //PermissionsModel.Instance.GetPermissionBits ( teamMember, teamMember.ModifiedBy, siteCollectionId, serverRelativeUrl, false );
                            PermissionsModel.GetGlobalPermissionBitsForCurrentUser ( teamMember, teamMember.ModifiedBy, siteCollectionId, serverRelativeUrl, false );

                            if ( teamMember.PermissionBitsTeams != null && teamMember.PermissionBitsTeams.Count > 0 )
                            {
                                bool canCreateProject = teamMember.PermissionBitsProjects[0];
                                bool canReadProject = teamMember.PermissionBitsProjects[1];
                                bool canUpdateProject = teamMember.PermissionBitsProjects[2];
                                bool canDeleteProject = teamMember.PermissionBitsProjects[3];

                                new TeamMemberValidator().Validate(teamMember);
                                if ( teamMember.IsValid ( ) )
                                {
                                    new TeamMemberValidator ( ).Validate ( teamMember, project, AssignedWorkCount ( teamMember, siteCollectionId, project.ServerRelativeWebUrl ) );

                                    if (teamMember.IsValid())
                                    {
                                        User user = teamMember.User;

                                        if ( canCreateProject || canUpdateProject )
                                        {
                                            if ( !PermissionsModel.SetProjectGroups ( siteCollectionId, serverRelativeUrl, teamMember ) )
                                                throw new Exception (
                                                    string.Format ( "An error occured while performing SPGroup management for {0} "
                                                        + "(Id: {1}). Please check the log and try again.", user.FullName, user.Id ) );
                                        }

                                        TeamDA.Instance.Save(teamMember, siteCollectionId, serverRelativeUrl);

                                        if (project != null && user != null)
                                        {
                                            //teamMember.ModifiedBy has the DIsplay Name of the User on the Email
                                            SendEmail(teamMember, project.Title, siteCollectionId, serverRelativeUrl, teamMember.ModifiedBy);
                                            UserModel.UpdateUserProjectIds(user, siteCollectionId, serverRelativeUrl, project.Id, teamMember.EditType);
                                            ProjectsModel.UpdateProjectManagerIds(project, siteCollectionId, serverRelativeUrl, user.Id, teamMember.EditType, teamMember.IsProjectManager);
                                        }
                                    }
                                }
                            }
                            else
                                throw new KiiroUnauthorizedAccessException ( "Updating Team Failed: Access Denied." );
                        }
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, true );
            }

            return members;
        }

        public static TeamMember Save ( TeamMember teamMember, Guid siteCollectionId, string serverRelativeUrl )
        {
            List<TeamMember> members = Save ( new List<TeamMember> ( ) { teamMember }, null, siteCollectionId, serverRelativeUrl );
            return members.Count > 0 ? members [ 0 ] : null;
        }

        private static void SendEmail(TeamMember teamMember, string projectTitle, Guid siteCollectionId, string serverRelativeUrl, User currentUser)
        {
            string url = string.Empty;

            if ( teamMember.User != null && teamMember.User.ReceiveEmailNotification )
            {
                if ( teamMember.EditType == EditType.Deleted )
                {
                    using ( SPWeb web = SPHelpers.GetPortalWeb ( siteCollectionId, serverRelativeUrl ) )
                    {
                        url = EmailModel.Instance.FixUrlForUserZone(web.Url, teamMember.User);
                    }
                    string [ ] args = new string [ ] { projectTitle, url };
                    EmailModel.Instance.SendNotificationEmail(EmailModel.EmailType.TeamRemoval, teamMember.User.Email, args, currentUser);
                }
                else if (teamMember.EditType == EditType.Created)
                {
                    using ( SPWeb web = SPHelpers.GetWeb ( siteCollectionId, serverRelativeUrl ) )
                    {
                        url = EmailModel.Instance.FixUrlForUserZone ( web.Url, teamMember.User );
                    }
                    string [ ] args = new string [ ] { projectTitle, teamMember.RoleOnProject, url };
                    EmailModel.Instance.SendNotificationEmail(EmailModel.EmailType.TeamAssignment, teamMember.User.Email, args, currentUser);
                }
            }            
        }

        private static int AssignedWorkCount(TeamMember teamMember, Guid siteCollectionId, string serverRelativeUrl)
        {
            List<Work> work = WorkModel.GetMyWork(siteCollectionId, serverRelativeUrl, teamMember.User);
            return work != null ? work.Count : default ( int );
        }


        internal static void CreateInitialProjectTeam ( Project project, Guid siteCollectionId, string serverRelativeUrl )
        {
            List<TeamMember> members = new List<TeamMember>();

            TeamMember teamMember = new TeamMember ( );
            teamMember.UserId = project.CreatedBy.Id;
            teamMember.RoleOnProject = "Project Manager";
            teamMember.IsProjectManager = true;
            teamMember.CreatedBy = project.CreatedBy;
            teamMember.ModifiedBy = project.CreatedBy;
            teamMember.CreatedDate = DateTime.Now;
            teamMember.ModifiedDate = DateTime.Now;
            teamMember.User = project.CreatedBy;

            members.Add(teamMember);

            List<User> users = UserModel.GetAddToAllProjectsUsers ( siteCollectionId, serverRelativeUrl );

            if ( users != null )
            {
                foreach ( User user in users )
                {
                    if ( user.Id != project.CreatedBy.Id )
                    {
                        teamMember = new TeamMember ( );
                        teamMember.UserId = user.Id;
                        teamMember.RoleOnProject = "Team Member";
                        teamMember.CreatedBy = project.CreatedBy;
                        teamMember.ModifiedBy = project.CreatedBy;
                        teamMember.CreatedDate = DateTime.Now;
                        teamMember.ModifiedDate = DateTime.Now;
                        teamMember.User = user;

                        members.Add(teamMember);
                    }
                }
            }

            Save ( members, project, siteCollectionId, serverRelativeUrl );
        }       
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.Model/TeamModel.cs $
 * 
 * 18    2/08/10 5:04p Camerons
 * 
 * 17    1/25/10 1:17p Camerons
 * 
 * 16    1/12/10 12:03p Camerons
 * 
 * 15    26/11/09 10:35a Camerons
 * 
 * 14    17/11/09 6:46p Camerons
 * 
 * 13    29/10/09 2:55p Camerons
 * 
 * 12    10/23/09 2:11p Adamw
 * 
 * 11    10/02/09 10:46a Stefanf
 * 
 * 10    21/09/09 3:30p Camerons
 * First batch of changes for 1.1.x.x - Security groups update
 * 
 * 9     4/09/09 10:24a Camerons
 * 
 * 8     17/08/09 10:29a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/